로딩 중이에요... 🐣
21 데이터클래스사용 | ✅ 저자: 이유정(박사)
Data Class란?
Python의 @dataclass
는 데이터 저장용 클래스를 짧고 간단하게 만들 수 있도록 도와주는 기능입니다.
- 원래 클래스는
__init__
,__repr__
,__eq__
같은 메서드를 직접 작성해야 했습니다. - 그런데
@dataclass
를 붙이면, 그런 귀찮은 코드를 자동으로 만들어줍니다!
__init__
: 객체가 생성될 때 실행되는 메서드( 읽기: 던더 이닛)
class Item:
def __init__(self, name, price):
self.name = name
self.price = price
역할:
- 클래스로 객체를 만들 때 자동으로 호출되는 생성자입니다.
Item("사과", 1000)
처럼 클래스를 호출하면__init__()
이 실행되어name
과price
를 저장합니다.
비유:
"아이템을 만들 때 이름표와 가격표를 붙여주는 역할"
__repr__
: 객체를 출력할 때 보여줄 문자열을 정의 ( 읽기: 던더 래퍼)
class Item:
def __init__(self, name, price):
self.name = name
self.price = price
def __repr__(self):
return f"Item(name={self.name}, price={self.price})"
item = Item("사과", 1000)
print(item)
출력결과:
Item(name=사과, price=1000)
print(item)
→ 내부적으로는item.__repr__()
을 호출함.__repr__()
에서f"Item(name={self.name}, price={self.price})"
를 반환함.- 즉, 문자열로 변환해서 보여주는 거예요.
만약 __repr__
가 없다면:
class Item:
def __init__(self, name, price):
self.name = name
self.price = price
item = Item("사과", 1000)
print(item)
출력결과:
<__main__.Item object at 0x7fc4b7d4dbb0>
즉, 메모리 주소만 보이는 기본 객체원형 출력 형태가 나와요.
역할:
print(item)
또는 디버깅할 때, 객체의 내용을 사람이 읽기 쉽게 보여줍니다.__str__()
와 비슷하지만__repr__()
은 디버깅용으로 더 정밀한 표현을 목표로 합니다.
비유:
"출력할 때 예쁘게 보여주는 명함"
__eq__
: 객체끼리 같은지 비교할 때 사용 (읽기:던더 이퀄)
class Item:
def __init__(self, name, price):
self.name = name
self.price = price
def __eq__(self, other):
return self.name == other.name and self.price == other.price
# 두 개의 인스턴스를 비교
item1 = Item("Notebook", 1000)
item2 = Item("Notebook", 1000)
item3 = Item("Pen", 500)
print(item1 == item2) # True
print(item1 == item3) # False
출력결과:
True
False
==
연산자는 내부적으로__eq__()
메서드를 호출합니다.item1 == item2
일 때, 두 객체의name
과price
가 같으므로True
.item1 == item3
일 때,name
이나price
중 하나라도 다르므로False
.
역할:
item1 == item2
처럼 비교할 때 내용이 같은지 판단하는 기준을 정의합니다.- 기본값은 두 객체의 메모리 주소를 비교하지만,
__eq__
을 재정의하면 값으로 비교할 수 있습니다.
비유:
"이 두 사람이 같은 사람인지 확인하는 신분증 검사"
예시로 이해해보기 Python에서 사용되는 일반 클래스 (귀찮음)
class Item:
def __init__(self, name, price):
self.name = name
self.price = price
def __repr__(self):
return f"Item(name={self.name}, price={self.price})"
Python에서 데이터를 담는 클래스를 더 간단히 만들고 싶을 때 – Data Class (간단함!)
from dataclasses import dataclass
@dataclass
class Item:
name: str
price: float
@dataclass
를 사용하면 __init__
, __repr__
, __eq__
같은 메서드를 자동으로 생성해주기 때문에 코드가 훨씬 간단해지고, 데이터 중심 객체를 만들기 쉬워집니다.
왜 필요한가?
코드 간결함
: init, repr 안 써도 됨
테스트 쉬움
: 비교, 출력, 변환이 편리
가독성 좋음
: 순수 데이터 구조를 깔끔하게 표현
자동 기능
: 타입 힌트 + 기본값 + 비교 연산 다 자동 제공
기본 Data Class 예제
예제: 책(Book) 정보를 담는 클래스
# book_test.py
from dataclasses import dataclass
# 책의 정보를 담는 데이터 클래스 정의
@dataclass
class Book:
title: str
author: str
price: float
# 객체 생성
book = Book("데이터 클래스란?", "이상한 나라의 코딩", 15.99)
# 출력해보기
print(book)
실행 결과:
Book(title='데이터 클래스란?', author='이상한 나라의 코딩', price=15.99)
복잡한 __init__
, __repr__
같은 함수 없이 깔끔하게 클래스 정의 가능!
Data Class + 기본값 지정
예제: price
, in_stock
에 기본값을 줌
# product_test.py
from dataclasses import dataclass
@dataclass
class Product:
name: str
price: float = 0.0 # 기본값: 0.0
in_stock: bool = True # 기본값: True
item = Product("USB")
print(item)
실행결과:
Product(name='USB', price=0.0, in_stock=True)
생성자에서 name
만 넣어도 나머지는 기본값으로 자동 설정!
FastAPI에서 요청 데이터를 Data Class로 받기
FastAPI에서 @dataclass
를 사용하면 POST 요청으로 들어온 JSON 데이터를 객체로 변환해줍니다.
예제: 상품 등록 API
# item.py
from dataclasses import dataclass
from typing import Union
from fastapi import FastAPI
from fastapi import Body
app = FastAPI()
# 상품 정보를 담는 데이터 클래스
@dataclass
class Item:
name: str
price: float
description: Union[str, None] = None
@app.post("/items/")
async def create_item(item: Item = Body(...)):
return item
실행:
uvicorn item:app --reload
브라우저에서 http://localhost:8000/docs
접속
/items/
POST 테스트 → 아래와 같은 JSON 입력
# 요청
{
"name": "키보드",
"price": 39.99,
"description": "기계식 키보드"
}
# 응답
{
"name": "키보드",
"price": 39.99,
"description": "기계식 키보드"
}
FastAPI에서 응답을 Data Class로 반환
@dataclass
를 사용해도 response_model
로 응답 스키마를 정의할 수 있습니다.
# items.py
# Python의 dataclass 기능과 필드 설정 도구를 불러옴
from dataclasses import dataclass, field
# 타입 힌트를 위한 도구들 불러옴 (리스트, 선택적 값)
from typing import List, Union
# FastAPI 앱을 만들기 위한 객체 불러옴
from fastapi import FastAPI
# FastAPI 인스턴스 생성 → 이걸 기준으로 API 라우터 등록 가능
app = FastAPI()
# 데이터 클래스 정의 시작: 자동으로 __init__, __repr__ 등을 생성해줌
@dataclass
class Item:
# 이름: 문자열 (필수)
name: str
# 가격: 실수형 숫자 (필수)
price: float
# 태그: 문자열 리스트, 기본값은 빈 리스트
tags: List[str] = field(default_factory=list)
# 설명: 문자열 또는 None 가능 (기본값은 None)
description: Union[str, None] = None
# /items/ 경로에 대한 GET 요청 처리 함수 정의
# 응답 형식을 Item 데이터클래스로 지정 (자동으로 스키마 생성됨)
@app.get("/items/", response_model=Item)
async def get_item():
# 실제 반환할 데이터 딕셔너리 (Item 구조와 일치)
return {
"name": "Python 책",
"price": 29.99,
"description": "초보자를 위한 FastAPI",
"tags": ["프로그래밍", "API"]
}
실행:
uvicorn items:app --reload
/items/
에 GET 요청 시 JSON 응답:
{
"name": "Python 책",
"price": 29.99,
"description": "초보자를 위한 FastAPI",
"tags": ["프로그래밍", "API"]
}
이 코드는 FastAPI에서 @dataclass
를 활용해 응답 모델을 정의하고, /items/
경로로 요청하면 해당 데이터를 JSON 형식으로 반환하는 API를 만드는 예시입니다.
중첩된 Data Class 사용 (복잡한 구조도 가능) 예제: 작가(Author)와 책(Book)의 관계 표현
# books.py
# 필요한 모듈들을 불러옵니다.
from dataclasses import dataclass, field # 데이터 클래스를 만들기 위한 데코레이터와 필드 도구
from typing import List, Union # 타입 힌트를 위해 리스트, 유니언 타입 사용
from fastapi import FastAPI # FastAPI 애플리케이션 생성에 필요한 모듈
# FastAPI 애플리케이션 인스턴스를 생성합니다.
app = FastAPI()
# Book 클래스: 책 정보를 담는 데이터 클래스입니다.
# title은 필수(str), description은 선택(str 또는 None)
@dataclass
class Book:
title: str # 책 제목
description: Union[str, None] = None # 책 설명 (없을 수도 있음)
# Author 클래스: 작가 정보를 담고, 여러 권의 책(Book)을 가질 수 있습니다.
@dataclass
class Author:
name: str # 작가 이름
books: List[Book] = field(default_factory=list)
# 작가가 쓴 책들 리스트 (기본은 빈 리스트)
# GET 요청을 받을 수 있는 엔드포인트 "/authors/" 생성
# 응답(response_model)은 Author의 리스트 형태로 정의합니다.
@app.get("/authors/", response_model=List[Author])
async def get_authors():
# 작가 정보와 그들이 쓴 책들을 반환합니다. (딕셔너리 형태로 작성)
return [
{
"name": "이정수", # 작가 이름
"books": [ # 이 작가가 쓴 책들
{"title": "Python 개론", "description": "입문자를 위한 책"},
{"title": "FastAPI 완전정복"}
# description은 생략해도 None으로 처리됨
]
}
]
실행:
uvicorn books:app --reload
/authors/
GET 요청 결과:
[
{
"name": "이정수",
"books": [
{
"title": "Python 개론",
"description": "입문자를 위한 책"
},
{
"title": "FastAPI 완전정복",
"description": null
}
]
}
]
데이터 구조가 복잡해도 @dataclass
로 직관적으로 정의 가능!